package ru.usu.gv.utils.math;

import ru.usu.gv.utils.RandomUtilities;

/**
 * @author spupyrev
 * 08.11.2009
 */
public class Vector
{
	private double[] data;
	
	public Vector(Vector other)
	{
		this(other.data);
	}

	public Vector(double[] data)
	{
		copy(data);
	}

	public void copy(double[] data)
	{
		this.data = new double[data.length];
		for (int i = 0; i < data.length; i++)
			this.data[i] = data[i];
	}

	public void copy(Vector o)
	{
		copy(o.data);
	}

	public Vector(int count)
	{
		data = new double[count];
		for (int i = 0; i < count; i++)
			data[i] = 0;
	}

	public Vector()
	{
		this(0);
	}

	public int getCount()
	{
		return data.length;
	}
	
	public double get(int index)
	{
		return data[index];
	}

	public void set(int index, double value)
	{
		data[index] = value;
	}

	public void add(int index, double value)
	{
		data[index] += value;
	}

	//Gives a random unit Euclidean length vector of a given size
	public void initRandomUnitLengthVector(int size, int seed)
	{
		RandomUtilities.setSeed(seed);

		data = new double[size];
		for (int i = 0; i < size; i++)
			data[i] = RandomUtilities.nextDouble();

		normalize();
	}

	//Multiplies a vector with a scalar factor
	public void scale(double factor)
	{
		for (int i = 0; i < getCount(); i++)
			data[i] *= factor;
	}

	//Returns the sum of all entries
	public double sum()
	{
		double sum = 0;
		for (int i = 0; i < getCount(); i++)
			sum += data[i];

		return sum;

	}

	//Returns the mean of all entries
	public double mean()
	{
		if (getCount() == 0)
			return 0;
		return sum() / getCount();

	}

	//Gives the norm of a vector, that is, its length in
	//vector.length dimensional Euclidean space.
	public double norm()
	{
		double res = 0;
		for (int i = 0; i < getCount(); i++)
			res += data[i] * data[i];

		res = Math.sqrt(res);

		return res;

	}

	//Normalizes a vector to unit length (1.0) in
	//vector.length dimensional Euclidean space.
	//If the vector is the 0-vector, nothing is done.
	public double normalize()
	{
		double nm = norm();
		if (nm <= 0.0)
			return 0.0;
		scale(1.0 / nm);

		return nm;

	}

	//Gives the inner product of two vectors of the same size
	public double dot(Vector v)
	{
		assert (getCount() == v.getCount());
		double res = 0;
		for (int i = 0; i < getCount(); i++)
			res += data[i] * v.data[i];

		return res;

	}

	//Orthogonalizes a vector against another vector, so that their scalar product is 0
	public void orthogonize(Vector y)
	{
		assert (getCount() == y.getCount());
		double k = dot(y) / y.dot(y);
		for (int i = 0; i < getCount(); i++)
		{
			data[i] -= k * y.data[i];
		}

	}

}
